package cn.huaqingcheng.tool.core;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 存储单位
 */
@SuppressWarnings("unused")
public enum StorageUnit {
    BYTE(StorageUnit.BYTE_SIZE, "字节"),
    KB(StorageUnit.KB_SIZE, "千字节"),
    MB(StorageUnit.MB_SIZE, "兆字节"),
    GB(StorageUnit.GB_SIZE, "十亿字节"),
    TB(StorageUnit.TB_SIZE, "万亿字节"),
    PB(StorageUnit.PB_SIZE, "千万亿字节"),
    EB(StorageUnit.EB_SIZE, "EB");

    public static final long BYTE_SIZE = 1L;

    public static final long KB_SIZE = BYTE_SIZE << 10;

    public static final long MB_SIZE = KB_SIZE << 10;

    public static final long GB_SIZE = MB_SIZE << 10;

    public static final long TB_SIZE = GB_SIZE << 10;

    public static final long PB_SIZE = TB_SIZE << 10;

    public static final long EB_SIZE = PB_SIZE << 10;

    /* 可能有用的常数 -------------------------- */
    public static final long KB_128 = KB_SIZE << 7;

    public static final long KB_64 = KB_SIZE << 6;

    public static final long KB_4 = KB_SIZE << 2;

    private final long byteSize;

    @SuppressWarnings("FieldCanBeLocal")
    private final String name;

    /**
     * 构造
     *
     * @param byteSize 1单位字节数
     * @param name     名称
     */
    StorageUnit(long byteSize, String name) {
        this.byteSize = byteSize;
        this.name = name;
    }

    /**
     * 友好 toString, 根据 size 值范围, 自动切换输出单位
     *
     * @param size size
     * @return string
     */
    public static String fitToString(long size) {
        return confirmFit(size).toString(size);
    }

    /**
     * 判断 size 大小的字节 处于哪个单位区间
     *
     * @param size size
     * @return 单位
     */
    @SuppressWarnings("MethodWithMultipleReturnPoints")
    public static StorageUnit confirmFit(long size) {
        if (BYTE.fit(size)) {
            return BYTE;
        }
        if (KB.fit(size)) {
            return KB;
        }
        if (MB.fit(size)) {
            return MB;
        }
        if (GB.fit(size)) {
            return GB;
        }
        if (TB.fit(size)) {
            return TB;
        }
        if (PB.fit(size)) {
            return PB;
        }
        if (EB.fit(size)) {
            return EB;
        }
        throw new IllegalArgumentException("不合理的文件大小");
    }

    /**
     * 合适?
     * size 以当前单位表示时, 数值是否介于 [1 - 1024) 之间
     *
     * @param size size
     * @return 合适?
     */
    public boolean fit(long size) {
        if (size < 0) {
            return false;
        }
        double convert = tryToConvert(size);
        return convert >= 1 && convert < 1024;
    }

    /**
     * 以当前单位显示指定size
     *
     * @param size size
     * @return string
     */
    public String toString(long size) {
        BigDecimal scale = BigDecimal.valueOf(tryToConvert(size))
            .setScale(2, RoundingMode.DOWN);
        return "%s %s".formatted(scale, this);
    }

    /**
     * 尝试转换size为当前单位的数值
     *
     * @param size size
     * @return 转换后的数值
     */
    public double tryToConvert(long size) {
        return (size * 1.0D) / byteSize;
    }

    /**
     * amount 个当前单位, 代表多少千字节
     *
     * @param amount 数量
     * @return 千字节
     */
    public long toKb(int amount) {
        return toByte(amount) >> 10;
    }

    /**
     * amount 个 当前单位, 代表多少字节
     *
     * @param amount 数量
     * @return 字节数
     */
    public long toByte(int amount) {
        if (amount <= 0) {
            return 0;
        }
        return byteSize * amount;
    }
}
